import time
import os
import numpy as np
import pandas as pd
from keras.models import load_model
import pickle
import matplotlib.pyplot as plt
from sklearn.metrics import r2_score, mean_squared_error

start_time = time.time()

# 配置路径
testfile_path = r"F:\dataset\BQW_min\Group\A1_new\202502.csv"
model_path = r"F:\dataset\test\demo_train_v1\GeneratorWindingTemperature1_Model.h5"
scaler_path = r"F:\dataset\test\demo_train_v1\GeneratorWindingTemperature1_scaler.pkl"
output_folder = r'F:\dataset\test'
os.makedirs(output_folder, exist_ok=True)

# 参数配置（需要与训练时保持一致）
time_name = 'rectime'
target_name = 'V71'
need_names = ['V74', 'V73', 'V72', 'V76']
N_past_value = 30  # 与训练时一致
Pre_size = 30  # 预测步长
Lstm_input_size = len(need_names) + 1  # 特征数量


def inverse_scale_pred(pred_array, scaler, n_features):
    """正确的逆变换方法（与训练代码一致）"""
    samples, seq_len, _ = pred_array.shape

    # 重塑为2D数组进行逆变换
    pred_2d = pred_array.reshape(-1, 1)

    # 创建与scaler期望形状匹配的数组
    dummy_array = np.zeros((pred_2d.shape[0], n_features))
    dummy_array[:, 0] = pred_2d[:, 0]  # 将预测值放在第一列

    # 逆变换
    inverted_array = scaler.inverse_transform(dummy_array)

    # 提取目标列并恢复序列形状
    return inverted_array[:, 0].reshape(samples, seq_len)


def createXY(dataset, n_past, Pre_size, n_features):
    """创建时间序列样本（与训练代码一致）"""
    dataX = []
    dataY = []
    for i in range(n_past, len(dataset) - Pre_size):
        dataX.append(dataset[i - n_past:i, :])  # 所有特征
        dataY.append(dataset[i:i + Pre_size, 0])  # 只取目标变量
    return np.array(dataX), np.array(dataY)


def prepare_test_data(data, scaler, need_names, target_name):
    """准备测试数据"""
    # 确保列存在
    required_columns = [target_name] + need_names
    missing_columns = [col for col in required_columns if col not in data.columns]
    if missing_columns:
        raise ValueError(f"测试数据缺少必要的列: {missing_columns}")

    # 提取目标列和特征列
    target = data[[target_name]].values
    features = data[need_names].values

    # 合并并缩放
    full_data = np.concatenate([target, features], axis=1)
    scaled_data = scaler.transform(full_data)

    return scaled_data


def detailed_evaluation(original, pred, period_name=""):
    """详细评估模型性能"""
    print(f"\n=== {period_name}详细评估 ===")

    # 整体指标
    from sklearn.metrics import r2_score, mean_squared_error
    from keras.losses import mean_absolute_error

    overall_r2 = r2_score(original, pred)
    overall_mse = mean_squared_error(original, pred)
    overall_mae = mean_absolute_error(original, pred)
    overall_rmse = np.sqrt(overall_mse)

    print(f"整体指标:")
    print(f"  R²: {overall_r2:.4f}")
    print(f"  MSE: {overall_mse:.4f}")
    print(f"  MAE: {overall_mae:.4f}")
    print(f"  RMSE: {overall_rmse:.4f}")

    # 如果original是2D，计算每个预测步长的指标
    if len(original.shape) == 2:
        step_metrics = []
        for step in range(original.shape[1]):
            step_r2 = r2_score(original[:, step], pred[:, step])
            step_mse = mean_squared_error(original[:, step], pred[:, step])
            step_metrics.append((step + 1, step_r2, step_mse))

        print("\n各预测步长指标:")
        for step, r2, mse in step_metrics:
            print(f"  步长 {step}: R²={r2:.4f}, MSE={mse:.4f}")

    return overall_r2, overall_mse, overall_mae, overall_rmse


# 主预测流程
print("开始预测流程...")

# 加载测试数据
df_test = pd.read_csv(testfile_path)
print(f"测试数据尺寸：{df_test.shape}")

# 加载scaler和模型
with open(scaler_path, 'rb') as f:
    scaler = pickle.load(f)

model = load_model(model_path)
print("模型和scaler加载完成")

# 准备测试数据
test_scaled = prepare_test_data(df_test, scaler, need_names, target_name)

# 创建测试样本
testX, testY = createXY(test_scaled, N_past_value, Pre_size, Lstm_input_size)

print(f"测试样本形状: testX: {testX.shape}, testY: {testY.shape}")

# 进行批量预测
print("进行批量预测...")
predictions = model.predict(testX)
print(f"预测结果形状: {predictions.shape}")

# 正确的逆变换
pred = inverse_scale_pred(predictions, scaler, Lstm_input_size)
original = inverse_scale_pred(testY.reshape(testY.shape[0], testY.shape[1], 1), scaler, Lstm_input_size)

# 展平以计算整体指标
pred_flat = pred.flatten()
original_flat = original.flatten()

print(f"逆变换后形状 - 真实值: {original_flat.shape}, 预测值: {pred_flat.shape}")

# 详细评估
test_r2, test_mse, test_mae, test_rmse = detailed_evaluation(original_flat, pred_flat, "测试集")

# 可视化预测结果
plt.figure(figsize=(15, 10))

# 整体预测对比（显示前500个点）
plt.subplot(2, 2, 1)
sample_points = min(500, len(original_flat))
plt.plot(original_flat[:sample_points], label='真实值', alpha=0.7, linewidth=1)
plt.plot(pred_flat[:sample_points], label='预测值', alpha=0.7, linewidth=1)
plt.title(f'测试集预测对比 (前{sample_points}个点)')
plt.xlabel('时间步')
plt.ylabel('值')
plt.legend()

# 散点图
plt.subplot(2, 2, 2)
plt.scatter(original_flat, pred_flat, alpha=0.5, s=1)
min_val = min(original_flat.min(), pred_flat.min())
max_val = max(original_flat.max(), pred_flat.max())
plt.plot([min_val, max_val], [min_val, max_val], 'r--', linewidth=1)
plt.xlabel('真实值')
plt.ylabel('预测值')
plt.title('预测值 vs 真实值')

# 残差图
plt.subplot(2, 2, 3)
residuals = original_flat - pred_flat
plt.scatter(pred_flat, residuals, alpha=0.5, s=1)
plt.axhline(y=0, color='r', linestyle='--', linewidth=1)
plt.xlabel('预测值')
plt.ylabel('残差')
plt.title('残差分析')

# 误差分布
plt.subplot(2, 2, 4)
plt.hist(residuals, bins=50, alpha=0.7)
plt.xlabel('残差')
plt.ylabel('频数')
plt.title('误差分布')

plt.tight_layout()
plt.savefig(os.path.join(output_folder, 'comprehensive_prediction_evaluation.png'), dpi=300, bbox_inches='tight')
plt.show()

'''# 保存详细结果
results = pd.DataFrame({
    'TrueValue': original_flat,
    'PredictedValue': pred_flat,
    'Residual': residuals
})

results_path = os.path.join(output_folder, 'detailed_prediction_results.csv')
results.to_csv(results_path, index=False)
print(f"详细结果已保存至: {results_path}")

# 保存评估指标
metrics_summary = pd.DataFrame({
    'Metric': ['R²', 'MSE', 'MAE', 'RMSE'],
    'Value': [test_r2, test_mse, test_mae, test_rmse]
})

metrics_path = os.path.join(output_folder, 'prediction_metrics.csv')
metrics_summary.to_csv(metrics_path, index=False)
print(f"评估指标已保存至: {metrics_path}")
'''
end_time = time.time()
print(f"\n代码运行时间：{end_time - start_time:.2f}秒")

print("\n=== 预测完成 ===")
print(f"测试集R²: {test_r2:.4f}")
print(f"测试集RMSE: {test_rmse:.4f}")
print(f"测试集MAE: {test_mae:.4f}")

# 随机选择几个样本进行详细分析
print("\n=== 随机样本详细分析 ===")
np.random.seed(42)  # 保证可重复性
sample_indices = np.random.choice(len(testX), min(5, len(testX)), replace=False)

for i, idx in enumerate(sample_indices):
    sample_pred = pred[idx]
    sample_true = original[idx]

    plt.figure(figsize=(10, 4))
    plt.plot(sample_true, label='真实值', marker='o', markersize=3)
    plt.plot(sample_pred, label='预测值', marker='x', markersize=3)
    plt.title(f'样本 {idx} 的 {Pre_size} 步预测')
    plt.xlabel('预测步长')
    plt.ylabel('值')
    plt.legend()
    plt.savefig(os.path.join(output_folder, f'sample_{idx}_prediction.png'), dpi=300, bbox_inches='tight')
    plt.show()

    sample_r2 = r2_score(sample_true, sample_pred)
    print(f"样本 {idx}: R² = {sample_r2:.4f}")